#ifndef SETMAGNETLOCATION
#define SETMAGNETLOCATION

#pragma once
#include <iostream>
#include "Particle.h"
#include <vector>

class SetMagnetLocation {

	friend int main();

private:

	bool *m_range;
	int m_width, m_height;
	int m_length;

	int *m_object_map;
	std::vector<int> m_object_list;

	int *m_varx, *m_vary;
	float *m_varx_d, *m_vary_d;
	float *m_varx_dd, *m_vary_dd;

	float *m_field;

	struct __Magnet {
		Vector2 pos;
		Vector2 mm;
	};

	struct __Pos {
		int x,y;
		__Pos() { x=0; y=0; };
		__Pos(int _x, int _y) {x=_x; y=_y; };
		
		__forceinline __Pos operator + (__Pos& p) {
			return __Pos(x+p.x, y+p.y);
		}
		__forceinline __Pos operator - (__Pos& p) {
			return __Pos(x-p.x, y-p.y);
		}

		__forceinline __Pos operator / (int i) {
			return __Pos(x/i, y/i);
		}


		__forceinline __Pos& operator /= (int i) {
			*this = *this / i;
			return (*this);
		}
	};

	std::vector<__Magnet> m_magnet;

public:

	SetMagnetLocation(int width, int height, bool* range) {
		m_width = width;
		m_height = height;
		m_length = width * height;

		m_range = new bool[m_length];
		m_object_map = new int[m_length];
		
		m_field = new float[m_length];

		m_varx = new int[m_width];
		m_varx_d = new float[m_width];
		m_varx_dd = new float[m_width];
		m_vary = new int[m_height];
		m_vary_d = new float[m_height];
		m_vary_dd = new float[m_height];

		memcpy(m_range, range, sizeof(bool) * m_length);

	}
	
	~SetMagnetLocation() {
		delete [] m_range;
		delete [] m_varx;
		delete [] m_varx_d;
		delete [] m_varx_dd;
		delete [] m_vary;
		delete [] m_vary_d;
		delete [] m_vary_dd;
	}

	void ComputeMagnetPos();


	void CreateObjectMap();

	void CreateVarList(int obj_id);
	void SmoothVardCurve(float* curve, int length, int iteration);
	void SmoothField(float* field, int offset_x, int offset_y, int width, int height, int iteration);

	__Pos GetCenterOfObject(int obj_id);

	void PushMagnets(__Pos center, Vector2 dir, int thick, int length);

	int FindMaxValueDirection(__Pos pos, float* listx, float* listy);

	// move pos 1 pixel by direction, which means that 
	// 0 is x-1, 1 is x+1, 2 is y-1, 3 is y+1
	bool MovePos(__Pos &pos, int direction);

	float GetFieldDerv_x(int idx, float *field, int width, int height);
	float GetFieldDerv_y(int idx, float *field, int width, int height);

	int FindNearDirection_x(int idx, float *field, int width, int height);
	int FindNearDirection_y(int idx, float *field, int width, int height);

	void RemoveFromMagnet();

	// return true if (x,y) has near another object
	bool FindNearPixel(int obj_id, int x, int y);

	void FillObjectToAnother(int org_id, int oth_id);

	__forceinline int PosToIdx(int x, int y) {
		if (x<0 || y<0 || x>=m_width || y>=m_height)
			return -1;
		else
			return x + y * m_width;
	}
	__forceinline int PosToIdx(__Pos pos) {
		return PosToIdx(pos.x, pos.y);
	}
	__forceinline __Pos IdxToPos(int idx) {
		__Pos pos;
		pos.x = idx % m_width;
		pos.y = idx / m_width;
		return pos;
	}


	void PrintObjectMap() {
		int idx=0;
		for (int i=0; i<m_width; i++) {
			for (int j=0; j<m_height; j++) {
				printf("%d ", m_object_map[idx++]);
			}
			printf("\n");
		}

		printf("\n");
	}
	void PrintVar() {
		for (int x=0; x<m_width; x++) 
			printf("%d ", m_varx[x]);
		printf("\n");
		for (int x=0; x<m_width; x++) 
			printf("%.3f ", m_varx_d[x]);
		printf("\n");
		for (int y=0; y<m_height; y++) 
			printf("%d ", m_vary[y]);
		printf("\n");
		for (int y=0; y<m_height; y++) 
			printf("%.3f ", m_vary_d[y]);
		printf("\n");
	}
	void PrintField() {
		int idx=0;
		for (int i=0; i<m_width; i++) {
			for (int j=0; j<m_height; j++) {
				printf("%2.2f\t", m_field[idx++]);
			}
			printf("\n");
		}

		printf("\n");
	}

	void PrintFloatField(float* f) {
		int idx=0;
		for (int i=0; i<m_width; i++) {
			for (int j=0; j<m_height; j++) {
				printf("%2.2f\t", f[idx++]);
			}
			printf("\n");
		}

		printf("\n");
	}
};


#endif
